﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using LeakView.common;
using LeakView.database;
using LeakView.misc;
using LeakView.misc.view;
using LeakView.service;
using log4net;

namespace LeakView.view
{
    public partial class ViewMisc : UserControl
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Program));

        private bool demo = false;

        private double sc10min_high = double.NaN;
        private double sc10min_low = double.NaN;
        private double yc_high = double.NaN;
        private double yc_low = double.NaN;

        public ViewMisc()
        {
            InitializeComponent();

            if(!CSharpUtilities.IsDesignMode())
            {
                this.timer.Enabled = true;
            }

            //this.labelHead.Text = MiscModal.me.HeadName;
            //this.labelTail.Text = MiscModal.me.TailName;

            updateConfig();

            var table = new DataTable();
            table.Columns.Add("value", typeof(int));
            table.Columns.Add("title", typeof(string));

            table.Rows.Add(new object[] { 30, "30分钟" });
            table.Rows.Add(new object[] { 60, "1小时" });
            table.Rows.Add(new object[] { 120, "2小时" });

            this.comboBox1.DataSource = table;
            this.comboBox1.ValueMember = "value";
            this.comboBox1.DisplayMember = "title";

            this.comboBox1.SelectedValueChanged += ComboBox1_SelectedValueChanged;

        }

        private void ComboBox1_SelectedValueChanged(object sender, EventArgs e)
        {
            if(this.comboBox1.SelectedValue is int val)
            {
                Miscs.MiscChartTimeMinutes = val;
                this.ylPanel1.UpdateTimeRange();
                this.lsPanel1.UpdateTimeRange();
                this.scPanel1.UpdateTimeRange();
            }
        }

        private void updateConfig()
        {
            AnyConfig config = AnyConfigs.get("MISC");
            this.sc10min_high = config.get("SC_MAX").GetOrDefault(double.NaN);
            this.sc10min_low = config.get("SC_MIN").GetOrDefault(double.NaN);
            this.yc_high = config.get("YC_MAX").GetOrDefault(double.NaN);
            this.yc_low = config.get("YC_MIN").GetOrDefault(double.NaN);
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            this.timer.Enabled = false;

            try
            {
                try
                {
                    DateTime now = DateTime.Now;

                    double speedHead = MiscModal.me.GetValue(MiscType.HeadLS);
                    double speedTail = MiscModal.me.GetValue(MiscType.TailLS);

                    double sc10min = MiscModal.me.GetValue(MiscType.Delta10M);
                    //this.labelDelta10m.Text = sc10min.ToString("F3") + " m³";
                    //this.labelDelta30m.Text = MiscModal.me.GetValue(MiscType.Delta30M).ToString("F3") + " m³";
                    //this.labelDelta60m.Text = MiscModal.me.GetValue(MiscType.Delta60M).ToString("F3") + " m³";

                    this.labelHeadTotal.Text = "上游总流量：" + MiscModal.me.GetValue(MiscType.HeadLL).ToString("F3") + " m³";
                    this.labelTailTotal.Text = "下游总流量：" + MiscModal.me.GetValue(MiscType.TailLL).ToString("F3") + " m³";
                    this.labelHeadWD.Text = "上游温度：" + MiscModal.me.GetValue(MiscType.HeadWD).ToString("F1") + " ℃";
                    this.labelTailWD.Text = "下游温度：" + MiscModal.me.GetValue(MiscType.TailWD).ToString("F1") + " ℃";

                    double headYL = MiscModal.me.GetValue(MiscType.HeadYL);
                    double tailYL = MiscModal.me.GetValue(MiscType.TailYL);
                    double deltaYL = tailYL - headYL;

                    // 判断报警
                    var sc = IsValueInRange(sc10min, sc10min_low, sc10min_high);
                    if(sc != 0 && !AlarmModal.me.AlarmForSC.IsAlarm)
                    {
                        Entities.AddMiscAlarm(
                            "输差",
                            sc == 1 ? "HIGH" : sc == 2 ? "LOW" : "NOVALUE",
                            sc10min.ToString(),
                            sc == 1 ? sc10min_high.ToString() : sc == 2 ? sc10min_low.ToString() : "NONE"
                            );
                    }
                    AlarmModal.me.AlarmForSC.IsAlarm = sc != 0;

                    var yc = IsValueInRange(deltaYL, yc_low, yc_high);
                    if (yc != 0 && !AlarmModal.me.AlarmForYC.IsAlarm)
                    {
                        Entities.AddMiscAlarm(
                            "压差",
                            yc == 1 ? "HIGH" : yc == 2 ? "LOW" : "NOVALUE",
                            deltaYL.ToString(),
                            yc == 1 ? yc_high.ToString() : yc == 2 ? yc_low.ToString() : "NONE"
                            );
                    }
                    AlarmModal.me.AlarmForYC.IsAlarm = yc != 0;

                    //AlarmModal.me.AlarmForSC.IsAlarm = !IsValueInRange(sc10min, sc10min_low, sc10min_high); // 设置输差报警状态
                    //AlarmModal.me.AlarmForYC.IsAlarm = !IsValueInRange(deltaYL, yc_low, yc_high); // 设置压差报警状态

                    //charts.feedCharts(now);

                    this.scPanel1.UpdateChart(now);
                    this.ylPanel1.UpdateChart(now);
                    this.lsPanel1.UpdateChart(now);

                }
                catch (Exception ex)
                {
                    log.Error("Exception on miscing.", ex);
                }

            }
            finally
            {
                this.timer.Enabled = true;
            }


        }


        public int IsValueInRange(double value, double min, double max)
        {
            // 如果最大值和最小值都没有设置，不做报警
            if(double.IsNaN(max) && double.IsNaN(min))
            {
                return 0;
            }

            if (double.IsNaN(value))
                return 3;

            if (!double.IsNaN(max) && value > max)
            {
                return 1;
            }

            if (!double.IsNaN(min) && value < min)
            {
                return 2;
            }

            return 0;
        }


        private void Button1_Click(object sender, EventArgs e)
        {
            /*
            if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
            {
                var f = new FormMiscHistory();
                f.Show();
            }
            else
            {
                var f = new FormMiscHistory2();
                f.Show();
            }
            */

            FormMiscHistory f = new FormMiscHistory();
            f.Show();

        }

        private void labelPipename_DoubleClick(object sender, EventArgs e)
        {
            if((Control.ModifierKeys & Keys.Control) == Keys.Control)
                demo = !demo;
        }

        private void labelPipename_Click(object sender, EventArgs e)
        {

        }

        private void button2_Click(object sender, EventArgs e)
        {
            FormThreshold f = new FormThreshold();
            f.ShowDialog();
            updateConfig();
        }
    }

    class ChartsProxy
    {
        private const int MaxTryCount = 2;
        private readonly ValueChart valueChart;
        private readonly MiscType miscType;
        private bool ready = false;
        private int trycount = 0;
        
        public ChartsProxy(ValueChart chart, MiscType type)
        {
            this.valueChart = chart;
            this.miscType = type;
        }

        public bool Ready { get => ready; }

        public void Initialize()
        {
            if (Ready) return;

            Thread thread = new Thread(() => {

                var data = MiscModal.me.LoadHistoryToday(miscType);
                if (data != null)
                {                   
                    valueChart.Invoke(new Action(() =>
                    {
                        data.ForEach(t =>
                        {
                            valueChart.appendValue(
                                Tools.ConvertLongToDateTime(t.timestamp),
                                MiscModal.me.GetDoubleFromMiscValue(t));
                        });
                        valueChart.UpdateChart();
                        ready = true;
                    }));
                    
                }
                else
                {
                    trycount++;
                    if(trycount == MaxTryCount)
                    {
                        ready = true;
                    }
                }

            });
            thread.Start();
        }

        public void Feed(DateTime now)
        {
            if (Ready)
            {
                valueChart.appendValue(now, MiscModal.me.GetValue(miscType));
                valueChart.UpdateChart();
            }
            else
            {
                Initialize();
            }
        }

        public void Feed(DateTime now, double value)
        {
            valueChart.appendValue(now, value);
            valueChart.UpdateChart();
        }

    }

    class ChartsManager
    {
        readonly List<ChartsProxy> proxies = new List<ChartsProxy>();

        private readonly Random demoRandom = new Random(791112);

        public ChartsManager Register(ValueChart chart, MiscType type)
        {
            proxies.Add(new ChartsProxy(chart, type));
            return this;
        }

        public void feedCharts(DateTime now)
        {
            proxies.ForEach(proxy =>
            {
                proxy.Feed(now);
            });
        }

        public void feedChartsDemo()
        {
            DateTime now = DateTime.Now;
            proxies.ForEach(proxy =>
            {
                proxy.Feed(now, demoRandom.NextDouble() * 200);
            });
        }
    }

#if false
    class ChartsManager
    {
        Dictionary<ValueChart, bool> chartsReady = new Dictionary<ValueChart, bool>();
        Dictionary<ValueChart, MiscType> chartsType = new Dictionary<ValueChart, MiscType>();

        private Random demoRandom = new Random(791112);

        public ChartsManager Register(ValueChart chart, MiscType type)
        {
            chartsReady[chart]= false;
            chartsType[chart] = type;
            return this;
        }

        public void Initialize()
        {
            chartsType.Keys.ToList().ForEach(chart =>
            {
                Thread thread = new Thread(()=>{
                    
                    var data = MiscModal.me.LoadHistoryToday(chartsType[chart]);
                    if (data != null)
                    {
                        chart.Invoke(new Action(() =>
                        {
                            data.ForEach(t =>
                            {
                                chart.appendValue(Tools.ConvertLongToDateTime(t.Key), t.Value);
                            });
                            chartsReady[chart] = true;
                        }));
                    }
                    else
                    {
                        chartsReady[chart] = true;
                    }

                });
                thread.Start();

            });
        }

        public bool IsReady()
        {
            return !chartsReady.Values.ToList().Exists(flag =>
            {
                return flag == false;
            });
        }

        public void feedCharts(DateTime now)
        {
            if(IsReady())
            {
                chartsType.Keys.ToList().ForEach(chart =>
                {
                    chart.appendValue(now, MiscModal.me.GetValue(chartsType[chart]));
                });
            }
        }

        public void feedChartsDemo()
        {
            DateTime now = DateTime.Now;
            chartsType.Keys.ToList().ForEach(chart =>
            {
                chart.appendValue(now, demoRandom.NextDouble() * 200);
            });
        }
    } 
#endif
}
